// import './index.less'

// 定义食物类
class Food {
  element: HTMLElement

  constructor() {
    this.element = document.getElementById('food')! //不可能为空 +!
  }

  // 获取食物X轴坐标方法
  get X() {
    return this.element.offsetLeft
  }

  // 获取食物y轴坐标方法
  get Y() {
    return this.element.offsetTop
  }

  // 修改食物位置 随机生成 0-290 蛇移动一次就是一格10像素
  change() {
    // round 四舍五入 floor向下取整 Math.floor( Math.random() * 30 ) * 10
    let top = Math.round(Math.random() * 29) * 10
    let left = Math.round(Math.random() * 29) * 10
    this.element.style.left = left + 'px'
    this.element.style.top = top + 'px'
  }
}

// 定义积分牌类
class ScorePanel {
  score = 0
  level = 1
  scoreEle: HTMLElement
  levelEle: HTMLElement

  // 设置一个变量限制等级
  maxLevel: number

  // 多少分升级
  upScore: number

  constructor(maxLevel: number = 10, upScore: number = 10) {
    this.scoreEle = document.getElementById('score')!
    this.levelEle = document.getElementById('level')!
    this.maxLevel = maxLevel
    this.upScore = upScore
  }

  // 加分方法
  addScore() {
    this.score++
    this.scoreEle.innerHTML = this.score + ''
    // 判断分数是多少
    if (this.score % this.upScore === 0) {
      this.levelUp()
    }
  }

  // 升级方法
  levelUp() {
    if (this.level < this.maxLevel) {
      this.levelEle.innerHTML = ++this.level + ''
    }
  }
}

// 定义蛇类
class Snake {
  element: HTMLElement
  head: HTMLElement
  bodies: HTMLCollection

  constructor() {
    this.element = document.getElementById('snake')!
    this.head = document.querySelector('#snake>div') as HTMLElement
    this.bodies = this.element.getElementsByTagName('div')
  }

  // 获取蛇头坐标
  get X() {
    return this.head.offsetLeft
  }

  get Y() {
    return this.head.offsetTop
  }

  // 设置蛇头坐标
  set X(value: number) {
    // 新值旧值相同，直接返回
    if (this.X === value) {
      return
    }

    // 蛇撞墙
    if (value < 0 || value > 290) {
      throw new Error('蛇撞墙了!')
    }

    // 修改x是在修改水平坐标蛇在左右移动 蛇向左则不能向右掉头
    if (this.bodies[1] && (this.bodies[1] as HTMLElement).offsetLeft === value) {
      // 如果发生掉头，让蛇向反方向继续移动
      if (value > this.X) {
        value = this.X - 10
      } else {
        value = this.X + 10
      }
    }

    // 移动身体
    this.moveBody()

    this.head.style.left = value + 'px'

    // 检查撞到自己
    // this.checkHeadBody()
  }

  set Y(value: number) {
    // 新值旧值相同，直接返回
    if (this.Y === value) {
      return
    }

    if (value < 0 || value > 290) {
      throw new Error('蛇撞墙了!')
    }

    // 修改y是在修改垂直坐标蛇在上下移动 蛇向上则不能向下掉头
    if (this.bodies[1] && (this.bodies[1] as HTMLElement).offsetLeft === value) {
      // 如果发生掉头，让蛇向反方向继续移动
      if (value > this.Y) {
        value = this.Y - 10
      } else {
        value = this.Y + 10
      }
    }

    // 移动身体
    this.moveBody()

    this.head.style.top = value + 'px'

    // 检查撞到自己
    // this.checkHeadBody()
  }

  // 蛇加身体
  addBody() {
    // 向element中添加div
    this.element.insertAdjacentHTML('beforeend', '<div></div>')
  }

  // 蛇身体移动方法
  moveBody() {
    // 将后边身体设置为前边身体位置
    // 遍历获取所有身体
    for (let i = this.bodies.length - 1; i > 0; i--) {
      // 获取前边身体位置
      let X = (this.bodies[i - 1] as HTMLElement).offsetLeft;
      let Y = (this.bodies[i - 1] as HTMLElement).offsetTop;

      // 设置到当前身体
      (this.bodies[i] as HTMLElement).style.left = X + 'px';
      (this.bodies[i] as HTMLElement).style.top = Y + 'px';
    }
  }

  /* // 检查蛇头是否与身体相撞方法
  checkHeadBody() {
    // 获取所有身体，检查是否和蛇头坐标重叠
    for (let i = 1; i < this.bodies.length; i++) {
      let bd = this.bodies[i] as HTMLElement;
      if (this.X === bd.offsetLeft && this.Y === bd.offsetTop) {
        // 进入判断说明蛇头撞到了身体，游戏结束
        throw new Error('撞到自己了！');
      }
    }
  } */
}

// 游戏控制类
class GameControl {
  snake: Snake
  food: Food
  scorePanel: ScorePanel

  // 按键方向
  direction: String = ''
  // 记录游戏是否结束
  isLive = true

  constructor() {
    this.snake = new Snake()
    this.food = new Food()
    this.scorePanel = new ScorePanel()

    this.init()
  }

  // 游戏初始化
  init() {
    document.addEventListener('keydown', this.keydownHandler.bind(this))
    // 调用run方法 使蛇移动
    this.run()
  }

  // 键盘按下响应函数
  keydownHandler(event: KeyboardEvent) {
    this.direction = event.key
  }

  // 控制蛇移动方法
  run() {
    // 根据方向this.direction来使蛇位置变更
    // 获取蛇现在坐标
    let X = this.snake.X
    let Y = this.snake.Y

    // 根据按键方向修改坐标
    switch (this.direction) {
      case "ArrowUp":
      case "w":
        Y -= 10
        break;
      case "ArrowDown":
      case "s":
        Y += 10
        break;
      case "ArrowLeft":
      case "a":
        X -= 10
        break;
      case "ArrowRight":
      case "d":
        X += 10
        break;
    }

    // 检查蛇是否吃到食物
    this.checkEat(X, Y)

    try {
      // 修改蛇坐标
      this.snake.X = X
      this.snake.Y = Y
    } catch (e) {
      // 出现异常 游戏结束
      alert(e.message + ' GAME OVER')
      // 将isLive设置为flase
      this.isLive = false
    }

    // 开启定时调用
    this.isLive && setTimeout(this.run.bind(this), 300 - (this.scorePanel.level - 1) * 30)
  }

  // 检查蛇是否吃到食物方法
  checkEat(X: number, Y: number) {
    if (X === this.food.X && Y === this.food.Y) {
      // 食物位置变化
      this.food.change()
      // 分数增加
      this.scorePanel.addScore()
      // 蛇增加一节
      this.snake.addBody()
    }
  }
}

const gameControl = new GameControl()

// setInterval(()=>{
//   console.log(gameControl.direction);
// },1000)

